#ifndef LOGGER_HPP
#define	LOGGER_HPP

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <time.h>
#include <fcntl.h>

#define DEFAULT_LOG_NAME "log_file.txt"
#define log(lvl,msg) do{ Logger::instance() << Log(lvl,msg); }while(0)
#define get_time() Logger::instance().get_clocks()

enum err_lvl_enum{ ERR = 0, WARN, INF };

class Log{
    int err_lvl;
    std::string err_message;
    tm err_time;
public:
    Log(int error_level,const char *messg);
    Log(int error_level,std::string str);
    std::string what();
    int get_err_lvl(){ return err_lvl; };

};
Log::Log(int error_level,const char *messg):err_message(messg){
    err_lvl = error_level;
    time_t raw_time;
    raw_time = time(NULL);
    err_time = *(localtime(&raw_time));
}
Log::Log(int error_level,std::string str):err_message(str){
    err_lvl = error_level;
    time_t raw_time;
    raw_time = time(NULL);
    err_time = *(localtime(&raw_time));
}

std::string Log::what(){
    std::string output(err_message);
    switch (err_lvl){
        case ERR:
            output.insert(0,"ERROR ");
            break;
        case WARN:
            output.insert(0,"WARNING ");
            break;
        case INF:
            output.insert(0,"INFO ");
            break;
        default:
            output.insert(0,"UNKNOWN ");
            break;
    }
    output += ' ';
    output += asctime(&err_time);
    return output;
}

class Logger {
public:
        static Logger& instance();
        void flush();
        void init(const char *log_name,int max,bool echo);
        Logger& operator<<(Log log);
        clock_t get_clocks();
        ~Logger();
protected:
        Logger(){};
        std::fstream log_stream;
        std::vector<Log> log_strg;
        unsigned int log_max;
        bool echo;
};

Logger& Logger::instance(){
    static Logger new_logger;
    return new_logger;
}

void Logger::init(const char *log_name,int max,bool echo){
	char default_name[] = DEFAULT_LOG_NAME;
	if(NULL == log_name)
            log_stream.open(default_name,std::ios::out);
        else
            log_stream.open(log_name,std::ios::out);
        log_max = max;
        this->echo = echo;
}
Logger& Logger::operator<<(Log log){
    log_strg.push_back(log);
    if(echo && log.get_err_lvl() < INF)
        std::cout << log.what();
    if(log_strg.size() == log_max)
        flush();
    return *this;
}
clock_t Logger::get_clocks(){
    return clock();
}
void Logger::flush(){
    for(unsigned int i = 0; i < log_strg.size(); i++){
        log_stream << log_strg[i].what();
    }
    log_stream.flush();
    log_strg.clear();
}
Logger::~Logger(){
    flush();
    log_stream.close();
}

#endif








